# -*- coding: utf-8 -*-
from datetime import datetime
import maya.mel as mel
import maya.cmds as cmds
import subprocess
import os
import time
import re
import tempfile
import shutil
import getpass
import ctypes
import sys
import logging
import traceback

# 创建一个日志记录器
logger = logging.getLogger ("mylogger")
logger.setLevel (logging.DEBUG)  # 设置处理器(Handler)处理的日志消息最低级别

# 创建一个文件处理器
file_handler = logging.FileHandler ('D:/my_log_file.log')
file_handler.setLevel (logging.INFO)

# 创建一个格式化器
formatter = logging.Formatter ("%(asctime)s - %(name)s - %(filename)s - %(levelname)s - %(funcName)s-%(lineno)d - %(message)s - %(pathname)s")
# 将格式化器添加到文件处理器
file_handler.setFormatter (formatter)
# 将文件处理器添加到日志记录器
logger.addHandler (file_handler)


class Playblast () :
    FFmpeg_PATH = "H:/RareWolf_Toolkit/Package/ffmpeg/ffmpeg.exe"

    def create_ass(self) :
        """
        创建ASS字幕文件。

        该方法通过Maya命令获取场景信息，如分辨率、帧率等，并利用FFmpeg创建带有时间码和动态信息（如场景名、日期、帧数等）的ASS字幕文件。
        """
        try :
            temp_folder = tempfile.gettempdir ()  # 获取临时文件夹路径
            type = "png"
            scenepath = cmds.file (q = 1 , sn = 1)  # 获取当前场景文件路径
            scenepathsp = scenepath.split ('/')
            scenename = scenepathsp[-1].split ('.')[0]  # 获取场景文件名（不包括扩展名）
            playblastTemp_folder = os.path.join (temp_folder , scenename).replace ("\\" , "/")  # 创建临时字幕文件夹路径
            outputPath_Directory = os.path.join (os.path.dirname (scenepath) , scenename + ".mov").replace ("\\" , "/")  # 创建输出文件路径
            # outputTempPath = os.path.join(playblastTemp_folder,scenename + ".mov").replace("\\", "/")

            i = 1920
            width = cmds.getAttr ("defaultResolution.w")  # 获取场景默认分辨率宽度
            if width % 10 == 7 :
                width += 1
            height = cmds.getAttr ("defaultResolution.h")  # 获取场景默认分辨率高度
            if height % 10 == 7 :
                height += 1
            Fontsize =  width *0.03# 根据场景宽度计算字体大小40 * (width / height)
            time_fps = cmds.currentUnit (q = 1 , t = 1)  # 获取当前时间单位（帧率）
            if time_fps == 'game' :
                fps = 15
            elif time_fps == 'film' :
                fps = 24
            elif time_fps == 'pal' :
                fps = 25
            elif time_fps == 'ntsc' :
                fps = 30
            elif time_fps == 'show' :
                fps = 48
            elif time_fps == 'palf' :
                fps = 50
            elif time_fps == 'ntscf' :
                fps = 60

            Fontname = "\u9ed1\u4f53"  # "Adobe Arabic"

            PrimaryColour = "&H0000FFFF"  # "&H00FFF8F8"   黄色"&H00FFFF00"  白色"&H00FFFAFA"
            SecondaryColour = "&H00FFFFFF"  # &HFFFF0000 "&H00DC143C"
            OutlineColour = "&HFFFFFFFF"  # "&H0000FFFF"
            BackColour = "&H00000000"
            BorderStyle = 1
            Outline = 0
            Shadow = 0

            assPath = os.path.join (playblastTemp_folder , scenename + ".ass").replace ("\\" , "/")
            exportpath = os.path.join (playblastTemp_folder , scenename).replace ("\\" , "/")
            inP = "-i " + exportpath + ".%04d.png"

            cmds.setAttr ('hardwareRenderingGlobals.gammaValue ' , 5)
            list_headsUpDisplay = cmds.headsUpDisplay (listHeadsUpDisplays = 1)
            if list_headsUpDisplay :
                for i in list_headsUpDisplay :
                    cmds.headsUpDisplay (i , remove = True)
            cmds.playblast (format = 'image' , filename = exportpath , sequenceTime = 0 , clearCache = 1 , viewer = 0 , showOrnaments = 1 , fp = 4 , percent = 100 , compression = type , quality = 100 , widthHeight = (
                width , height))

            hud_ass = ''
            hud_ass += "[Script Info]\n"
            hud_ass += "ScriptType: v4.00\n"
            hud_ass += "PlayResX: " + str (width) + "\n"
            hud_ass += "PlayResY: " + str (height) + "\n"
            hud_ass += "WrapStyle: 0\n"
            hud_ass += "[V4+ Styles]\n"
            hud_ass += "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n"
            hud_ass += u"Style: ProjSize,{},{},{},{},{},{},-1,0,0,0,60,60,0,0,{},{},{},8,0,0,10,134\n".format (str (Fontname) , str (Fontsize) , str (PrimaryColour) , str (SecondaryColour) , str (OutlineColour) , str (BackColour) , str (BorderStyle) , str (Outline) , str (Shadow))
            hud_ass += u"Style: Date,{},{},{},{},{},{},-1,0,0,0,60,60,0,0,{},{},{},7,10,0,10,134\n".format (str (Fontname) , str (Fontsize) , str (PrimaryColour) , str (SecondaryColour) , str (OutlineColour) , str (BackColour) , str (BorderStyle) , str (Outline) , str (Shadow))
            hud_ass += u"Style: FocalLength_text,{},{},{},{},{},{},-1,0,0,0,60,60,0,0,{},{},{},9,0,10,25,134\n".format (str (Fontname) , str (Fontsize) , str (PrimaryColour) , str (SecondaryColour) , str (OutlineColour) , str (BackColour) , str (BorderStyle) , str (Outline) , str (Shadow))
            hud_ass += u"Style: FileCam_text,{},{},{},{},{},{},-1,0,0,0,60,60,0,0,{},{},{},9,0,10,10,134\n".format (str (Fontname) , str (Fontsize) , str (PrimaryColour) , str (SecondaryColour) , str (OutlineColour) , str (BackColour) , str (BorderStyle) , str (Outline) , str (Shadow))
            hud_ass += u"Style: User,{},{},{},{},{},{},-1,0,0,0,60,60,0,0,{},{},{},1,10,0,10,134\n".format (str (Fontname) , str (Fontsize) , str (PrimaryColour) , str (SecondaryColour) , str (OutlineColour) , str (BackColour) , str (BorderStyle) , str (Outline) , str (Shadow))
            hud_ass += u"Style: PCName,{},{},{},{},{},{},-1,0,0,0,60,60,0,0,{},{},{},1,10,0,25,134\n".format (str (Fontname) , str (Fontsize) , str (PrimaryColour) , str (SecondaryColour) , str (OutlineColour) , str (BackColour) , str (BorderStyle) , str (Outline) , str (Shadow))
            hud_ass += u"Style: Scene_text,{},{},{},{},{},{},-1,0,0,0,60,60,0,0,{},{},{},2,0,0,10,134\n".format (str (Fontname) , str (Fontsize) , str (PrimaryColour) , str (SecondaryColour) , str (OutlineColour) , str (BackColour) , str (BorderStyle) , str (Outline) , str (Shadow))
            hud_ass += u"Style: TimeCode,{},{},{},{},{},{},-1,0,0,0,60,60,0,0,{},{},{},3,0,10,25,134\n".format (str (Fontname) , str (Fontsize) , str (PrimaryColour) , str (SecondaryColour) , str (OutlineColour) , str (BackColour) , str (BorderStyle) , str (Outline) , str (Shadow))
            hud_ass += u"Style: Frame_text,{},{},{},{},{},{},-1,0,0,0,60,60,0,0,{},{},{},3,0,10,10,134\n".format (str (Fontname) , str (Fontsize) , str (PrimaryColour) , str (SecondaryColour) , str (OutlineColour) , str (BackColour) , str (BorderStyle) , str (Outline) , str (Shadow))
            hud_ass += "\n"
            hud_ass += "[Events]\n"

            MinTimes = int (cmds.playbackOptions (q = 1 , minTime = 1))
            MaxTimes = int (cmds.playbackOptions (q = 1 , maxTime = 1))
            File_sceneName = cmds.file (q = 1 , sceneName = 1 , shortName = 1)
            PCName = os.environ.get ("COMPUTERNAME")
            hud_resolution = str (width) + " x " + str (cmds.getAttr ("defaultResolution.h"))
            frameRate = int (MaxTimes + 1 - MinTimes)
            all_camera = [i for i in cmds.listCameras (p = 1) if i != 'persp']
            obj_list = []
            playblastCame = ''

            for playblastCame in all_camera :
                if not cmds.referenceQuery (playblastCame , isNodeReferenced = True) :

                    obj_list.append (playblastCame)
                    playblastCame = obj_list[0]
            if cmds.listRelatives (playblastCame , p = 1) :
                CameraShape = playblastCame
            else :
                CameraShape = cmds.listRelatives (playblastCame , shapes = 1)[0]
            now = datetime.now ()
            Current_Date = now.strftime ('%Y/%m/%d %H:%M:%S')

            frame_duration = 1 / float (fps)
            for i in range (frameRate) :
                start_timecode = self.generate_ass_timecode (i , frame_duration)
                end_timecode = self.generate_ass_timecode (i + 1 , frame_duration)  # 结束时间码是下一帧的开始时间码
                current_timeconde = end_timecode
                CameFocalLength = cmds.getAttr (CameraShape + ".focalLength" , time = MinTimes + i)
                hud_ass += self.write_ass_file (i , start_timecode , end_timecode , playblastCame , hud_resolution , CameFocalLength , PCName , Current_Date , File_sceneName , current_timeconde , fps , MinTimes , MaxTimes)

            # hud_ass = hud_ass.encode('utf-8')
            version_info = sys.version_info
            if version_info.major == 2 :
                with open (assPath , 'w') as f :
                    f.write (hud_ass.encode ('utf-8'))
                    f.close ()

            elif version_info.major == 3 :
                with open (assPath , 'w' , encoding = 'utf-8') as f :
                    f.write (hud_ass)
                    f.close ()

            audioOffset = 0
            audioFileCmd = ''
            AudioList = []

            Audios = cmds.ls (type = "audio")
            aPlayBackSliderPython = mel.eval ('$tmpVar=$gPlayBackSlider')

            PlayBlastAudio = cmds.timeControl (aPlayBackSliderPython , q = 1 , s = 1)
            if PlayBlastAudio :
                AudioList.append (PlayBlastAudio)
            if len (Audios) == 1 :
                if len (AudioList) == 1 :
                    Audio = AudioList[0]
                    audioOffset = int (cmds.getAttr (Audio + ".offset") - MinTimes)
                    audioFile = cmds.sound (Audio , q = 1 , file = 1)
                else :
                    Audio = Audios[0]
                    audioOffset = int (cmds.getAttr (Audio + ".offset") - MinTimes)
                    audioFile = cmds.sound (Audio , q = 1 , file = 1)

                if not self.is_ascii (audioFile) :
                    print (u"音频路径存在中文")
                    pass

                offsetSec = float (audioOffset) / float (fps)
                offsetCmd = ''
                if audioOffset > 0 :
                    offsetCmd += "-itsoffset " + str (offsetSec) + " "
                else :
                    offsetCmd += "-ss " + str (abs (offsetSec)) + " "
                if len (audioFile) or os.path.exists (audioFile) :  # mel.eval('filetest - e audioFile')
                    audioFileCmd = offsetCmd + "-i " + audioFile

                if not os.path.isfile (audioFile) :
                    audioFileCmd = ''
            timeRange = "-t " + str ((MaxTimes - MinTimes + 1) / float (fps))
            s = " "
            start = "-start_number" + " " + str (MinTimes)
            femer = "-r" + " " + str (fps)
            converted_path = assPath.replace ("/" , "\\\\")
            converted_path = converted_path.replace (":" , "\\:")
            assPaths = assPath.split ("/")
            assP = ("-vf subtitles=" "\\\'" + converted_path + "\\\'")
            outP = "-c:v libx264 -b 18000k -pix_fmt yuv420p -crf 1 -y " + outputPath_Directory
            hudInfo = [start , femer , inP , audioFileCmd , timeRange , assP , outP]
            command_line = self.FFmpeg_PATH + " " + s.join (hudInfo)

            if version_info.major == 2 :
                os.popen (command_line)
            elif version_info.major == 3 :
                subprocess.Popen (command_line , shell = True , stdout = subprocess.PIPE , stderr = subprocess.PIPE)
            time.sleep (1.5)
            os.startfile (outputPath_Directory)
            shutil.rmtree (playblastTemp_folder)
        except Exception as e :
            traceback.print_exc ()  # 打印异常追踪信息
            logger.info ("创建ASS文件时出错: {}".format (e))

    def generate_ass_timecode(self , frame_number , frame_duration) :
        """
        根据帧号和帧时长生成ASS字幕格式的时间码字符串。

        参数:
            frame_number (int): 当前帧数。
            frame_duration (float): 单帧时长（秒）。

        返回:
            str: ASS时间码格式的字符串，如 "01:23:45.67"
        """
        current_time = frame_number * frame_duration
        hours = int (current_time // 3600)
        minutes = int ((current_time - (hours * 3600)) // 60)
        seconds = int (current_time - (hours * 3600) - (minutes * 60))
        milliseconds = int ((current_time - int (current_time)) * 100)
        return "{:01d}:{:02d}:{:02d}.{:02d}".format (hours , minutes , seconds , milliseconds)

    def week_day(self) :
        """
        获取当前日期对应的中文星期名。

        返回:
            str: 当前日期对应的中文星期名，如 "星期一"
        """
        now = datetime.now ()
        week = [u"星期一" , u"星期二" , u"星期三" , u"星期四" , u"星期五" , u"星期六" , u"星期日"]
        week_day = week[now.weekday ()]
        # utf8_week_day = week_day.encode('utf-8')
        time = now.strftime ('%Y/%m/%d %H:%M:%S')
        return (week_day)

    def is_ascii(self , string) :
        """
        判断给定字符串是否只包含ASCII字符。

        参数:
            string (str): 待检查的字符串。

        返回:
            bool: 如果字符串仅包含ASCII字符，返回True；否则返回False。
        """
        for char in string :
            if ord (char) > 127 :
                return False
        return True

    def getDisplayName(self) :
        """
        获取当前用户在Windows系统中的完整显示名称。

        返回:
            str: 当前用户的完整显示名称。
        """
        GetUserNameEx = ctypes.windll.secur32.GetUserNameExW
        NameDisplay = 3
        size = ctypes.pointer (ctypes.c_ulong (0))
        GetUserNameEx (NameDisplay , None , size)
        nameBuffer = ctypes.create_unicode_buffer (size.contents.value)
        GetUserNameEx (NameDisplay , nameBuffer , size)
        computerName = os.popen ('hostname').read ()
        return (nameBuffer.value)

    # return (u"社会康!")
    def getpass(self) :
        """
        获取当前登录用户的用户名。

        返回:
            str: 当前登录用户的用户名。
        """
        username = getpass.getuser ()
        return (username)

    def write_ass_file(self , i , start_timecode , end_timecode , playblast_came , hud_resolution , came_focal_length , pc_name , current_date , file_scene_name , current_timeconde , fps , min_times , max_times) :
        """
          生成ASS字幕文件内容字符串，包含指定的各项信息。

          参数:
              i (int): 未知用途的整数参数。
              start_timecode (str): 开始时间码。
              end_timecode (str): 结束时间码。
              playblast_came (str): 相机名称。
              hud_resolution (str): 文件分辨率。
              came_focal_length (str): 相机焦距字符串。
              pc_name (str): 计算机名。
              current_date (str): 当前日期字符串。
              file_scene_name (str): 文件或场景名。
              current_timeconde (str): 当前时间码。
              fps (int): 帧率。
              min_times (int): 时间滑条最小值。
              max_times (int): 时间滑条最大值。

          返回:
              str: 构建好的ASS字幕文件内容字符串。
          """
        hud_ass = ''
        hud_ass += u"Dialogue: 0,{},{},{},,0,0,0,,{}\n".format (str (start_timecode) , str (end_timecode) , "Frame_text" , str (min_times) + "/" + str (min_times + i) + "/" + str (max_times))
        hud_ass += u"Dialogue: 0,{},{},{},,0,0,0,,{}\n".format (str (start_timecode) , str (end_timecode) , "FileCam_text" , str (playblast_came))
        hud_ass += u"Dialogue: 0,{},{},{},,0,0,0,,{}\n".format (str (start_timecode) , str (end_timecode) , "ProjSize" , hud_resolution)
        hud_ass += u"Dialogue: 0,{},{},{},,0,0,0,,{}\n".format (str (start_timecode) , str (end_timecode) , "FocalLength_text" , str (came_focal_length))
        hud_ass += u"Dialogue: 0,{},{},{},,0,0,0,,{}\n".format (str (start_timecode) , str (end_timecode) , "User" , self.getDisplayName ())  # .encode("UTF-8")
        hud_ass += u"Dialogue: 0,{},{},{},,0,0,0,,{}\n".format (str (start_timecode) , str (end_timecode) , "PCName" , str (pc_name))
        hud_ass += u"Dialogue: 0,{},{},{},,0,0,0,,{}\n".format (str (start_timecode) , str (end_timecode) , "Date" , str (current_date) + self.week_day ())
        hud_ass += u"Dialogue: 0,{},{},{},,0,0,0,,{}\n".format (str (start_timecode) , str (end_timecode) , "Scene_text" , str (file_scene_name))
        hud_ass += u"Dialogue: 0,{},{},{},,0,0,0,,{}\n".format (str (start_timecode) , str (end_timecode) , "TimeCode" , current_timeconde + "(" + str (fps) + "fps)")
        return (hud_ass)


Playblast ().create_ass ()
